/*
 * The contents of this web application are subject to the Mozilla Public License Version 
 * 1.1 (the "License"); you may not use this web application except in compliance with 
 * the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/.
 * 
 * Software distributed under the License is distributed on an "AS IS" basis, 
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
 * for the specific language governing rights and limitations under the License.
 * 
 * The Original Code is owned by and the Initial Developer of the Original Code is 
 * Composite A/S (Danish business reg.no. 21744409). All Rights Reserved
 * 
 * Section 11 of the License is EXPRESSLY amended to include a provision stating 
 * that any dispute, including but not limited to disputes related to the enforcement 
 * of the License, to which Composite A/S as owner of the Original Code, as Initial 
 * Developer or in any other role, becomes a part to shall be governed by Danish law 
 * and be initiated before the Copenhagen City Court ("K�benhavns Byret")            
 */

/**
 * @class
 * @param @optional {Hashmap} map
 */
function Map ( map ) {

	/**
	 * @type {HashMap<object><object>
	 */	
	this._map = {};
	
	/*
	 * Populate from optional constructor object.
	 */
	if ( map != null ) {
		for ( var key in map ) {
			this.set ( key, map [ key ]);
		}
	}
}

Map.prototype._map = {};

/**
 * Get entry. Notice that an invalid key will not be tolerated 
 * here. Always use method "has" to check for key existance first.
 * @param {object} key
 */
Map.prototype.get = function ( key ) {
	
	var result = null;
	if ( this.has ( key )) {
		result = this._map [ key ];
	} else {
		var cry = "Map: Invalid key: " + key;
		SystemLogger.getLogger ( "Map" ).error ( cry );
		SystemDebug.stack ( arguments );
		if ( Application.isDeveloperMode ) {
			console.log(cry);
			console.log(arguments);
		}
	}
	return result;
}

/**
 * Set entry.
 * @param {object} key
 * @param {object} value
 */
Map.prototype.set = function ( key, value ) {
	
	this._map [ key ] = value;
}

/**
 * Delete entry.
 * @param {object} key
 */
Map.prototype.del = function ( key ) {
	
	delete this._map [ key ];
}

/**
 * Has entry?
 * @param {object} key
 * @return {boolean}
 */
Map.prototype.has = function ( key ) {
	
	return typeof this._map [ key ] != "undefined";
}

/**
 * Each entry.
 * @param {function} action
 */
Map.prototype.each = function ( action ) {
	
	for ( var key in this._map ) {
		var isContinue = action ( 
			key, 
			this._map [ key ]
		);
		if ( isContinue == false ) {
			break;
		}
	}
}

/**
 * Has entries?
 * @retun {boolean}
 */
Map.prototype.hasEntries = function () {
	
	var result = false;
	for ( var key in this._map ) {
		result = true;
		break;
	}
	return result;
}

/**
 * How many entries?
 * @retun {int}
 */
Map.prototype.countEntries = function () {
	
	var result = 0;
	for ( var key in this._map ) {
		result ++;
	}
	return result;
}

/** 
 * Convert to list (listing keys or values).
 * @param {boolean} isKey
 */
Map.prototype.toList = function ( isKey ) {
	
	var list = new List ();
	for ( var key in this._map ) {
		list.add (
			isKey ? key : this._map [ key ]
		);
	}
	return list;
}

/**
 * Copy.
 * @return {Map}
 */
Map.prototype.copy = function () {
	
	var map = new Map ();
	for ( var key in this._map ) {
		map.set ( key, this._map [ key ]);
	}
	return map;
}

/**
 * This will modify the original Map.
 * @return {Map}
 */
Map.prototype.inverse = function () {
	
	var map = new Map ();
	for ( var key in this._map ) {
		map.set ( this._map [ key ], key );
	}
	return map;
}

/**
 * Empty map.
 */
Map.prototype.empty = function () {
	
	for ( var key in this._map ) {
		delete this._map [ key ];
	}
}

/**
 * Dispose.
 * TODO: Invoke "dispose" on entries?
 */
Map.prototype.dispose = function () {
	
	for ( var key in this._map ) {
		this._map [ key ] = null;
	}
}